package org.scratchcrew.web.controller;

import java.util.regex.Pattern;

import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.validator.ValidatorException;

import org.scratchcrew.services.UserService;
import org.scratchcrew.web.jsf.FacesUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Scope;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Controller;

@Controller(value = "registerController")
@Scope(value = "request")
public class RegisterController {

	// The id of the Password field in the view.
	private static final String PASSWORD_COMPONENT_ID = "passwordComponentId";

	/**
	 * Key to the message indicating that password and confirm password do not
	 * match.
	 */
	private static final String PASS_NO_MATCH_MSG = "org.scratchcrew.web.controller.UserController.PASS_NO_MATCH_MSG";

	/**
	 * Key to the message indicating that user already exists.
	 */
	private static final String USER_EXISTS_MSG = "org.scratchcrew.web.controller.UserController.USER_EXISTS_MSG";

	/**
	 * Key to the message indicating that user name does not match the provided
	 * pattern.
	 */
	private static final String INVALID_USERNAME_MSG = "org.scratchcrew.web.controller.UserController.INVALID_USERNAME_MSG";

	/**
	 * The pattern that specifies correct user names.
	 */
	private static Pattern USER_REGEX;

	private String userName;
	private String password;

	@Autowired
	private UserService userService;

	@Autowired
	private MessageSource messageSource;

	@PostConstruct
	@SuppressWarnings("unused")
	private void init() {
		USER_REGEX = Pattern.compile(messageSource.getMessage("USER_REGEX",
				null, null));
	}

	/**
	 * Checks if submitted user name matches the provided pattern and if it is
	 * registered.
	 */
	public void validateUserName(FacesContext facesContext,
			UIComponent component, Object value) throws ValidatorException {
		String submitted = (String) value;
		if (!USER_REGEX.matcher(submitted).matches()) {
			throw new ValidatorException(new FacesMessage(messageSource
					.getMessage(INVALID_USERNAME_MSG, (Object[]) null,
							FacesUtils.getLocale())));
		}

		if (userService.exists(submitted)) {
			throw new ValidatorException(new FacesMessage(messageSource
					.getMessage(USER_EXISTS_MSG, new Object[] { FacesUtils
							.getLabel(component) }, FacesUtils.getLocale())));
		}
	}

	/**
	 * Check if password and confirm password match
	 */
	public void validateConfirmPassword(FacesContext facesContext,
			UIComponent component, Object value) throws ValidatorException {
		String passwordComponentId = (String) component.getAttributes().get(
				PASSWORD_COMPONENT_ID);
		UIInput passwordComponent = (UIInput) facesContext.getViewRoot()
				.findComponent(passwordComponentId);
		if (passwordComponent != null
				&& !value.equals(passwordComponent.getValue())) {
			throw new ValidatorException(new FacesMessage(messageSource
					.getMessage(PASS_NO_MATCH_MSG, new Object[] { FacesUtils
							.getLabel(component) }, FacesUtils.getLocale())));
		}
	}

	/**
	 * Creates the user in database.
	 */
	public void register(ActionEvent e) {
		try {
			userService.create(userName, password);
		} catch (DataIntegrityViolationException dive) {
			FacesContext.getCurrentInstance().addMessage(null,
					new FacesMessage(messageSource.getMessage(USER_EXISTS_MSG, (Object[])null, FacesUtils.getLocale())));
		}
	}

	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}
}
